﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LightCAD.Drawing.Actions.Action
{
    public class AxisLineAction : ElementAction
    {
        public AxisLineAction(IDocumentEditor docEditor)
    : base(docEditor)
        {
            LcDocument = docEditor.DocRt.Document;
        }
        public AxisLineAction() { }
        internal static void Initilize()
        {
            ElementActions.AxisLine = new AxisLineAction();
            LcDocument.ElementActions.Add(BuiltinElementType.AxisLine, ElementActions.AxisLine);
        }
        private PointInputer inputer { get; set; }
        public LcDocument LcDocument;
        public async void ExecCreate(string[] args = null)
        {
        }

        public override void Draw(SKCanvas canvas, LcElement element, Vector2 offSet)
        {
            Draw(canvas, element, Matrix3.GetTranslate(offSet));
        }
        public override void Draw(SKCanvas canvas, LcElement element, Matrix3 matrix)
        {
            var lcAxisLine = element as LcAxisLine;
            try
            {
                var lcLineAction = lcAxisLine.AxisLine.RtAction as ElementAction;
                lcLineAction.SetViewport(this.vportRt).Draw(canvas, lcAxisLine.AxisLine, matrix);
                if (lcAxisLine.StartLeadLines.Count > 0)
                {

                    var lcStartLine = lcAxisLine.StartLeadLines.FirstOrDefault() as LcLine;
                    lcStartLine.Start = lcAxisLine.AxisLine.Start;
                    //var lcStartLineAction = lcStartLine.RtAction as ElementAction;
                    //lcStartLineAction.SetViewport(this.vportRt).Draw(canvas, lcStartLine, matrix);
                    foreach (var leadLine in lcAxisLine.StartLeadLines)
                    {
                        var LeadLineAction = leadLine.RtAction as ElementAction;
                        LeadLineAction.SetViewport(this.vportRt).Draw(canvas, leadLine, matrix);
                    }
                }
                if (lcAxisLine.EndLeadLines.Count > 0)
                {
                    var lcEndLine = lcAxisLine.EndLeadLines.FirstOrDefault() as LcLine;
                    lcEndLine.Start = lcAxisLine.AxisLine.End;
                    foreach (var leadLine in lcAxisLine.EndLeadLines)
                    {
                        var LeadLineAction = leadLine.RtAction as ElementAction;
                        LeadLineAction.SetViewport(this.vportRt).Draw(canvas, leadLine, matrix);
                    }
                }
                foreach (LcAxisCircle lcAxisCircle in lcAxisLine.StartCircleHandle)
                {
                    //if (lcAxisCircle.LcText != null)
                    //{

                    //    var textAction = lcAxisCircle.LcText.RtAction as ElementAction;
                    //    textAction.SetViewport(this.vportRt).Draw(canvas, lcAxisCircle.LcText, matrix);
                    //}

                    var circleAction = lcAxisCircle.LcCircle.RtAction as ElementAction;
                    circleAction.SetViewport(this.vportRt).Draw(canvas, lcAxisCircle.LcCircle, matrix);
                }
                foreach (LcAxisCircle lcAxisCircle in lcAxisLine.EndCircleHandle)
                {
                    //var textAction = lcAxisCircle.LcText.RtAction as ElementAction;
                    //textAction.SetViewport(this.vportRt).Draw(canvas, lcAxisCircle.LcText, matrix);

                    var circleAction = lcAxisCircle.LcCircle.RtAction as ElementAction;
                    circleAction.SetViewport(this.vportRt).Draw(canvas, lcAxisCircle.LcCircle, matrix);
                }
            }

            catch (Exception ex)
            {
            }

            if (matrix == Matrix3.Identity)
            {
                //var leftTop = this.vportRt.ConvertWcsToScr(lcDrawing.BoundingBox.LeftTop);
                //var rightBottom = this.vportRt.ConvertWcsToScr(lcDrawing.BoundingBox.RightBottom);
                //canvas.DrawRect((float)leftTop.X, (float)leftTop.Y, (float)rightBottom.X - (float)leftTop.X, (float)rightBottom.Y - (float)leftTop.Y, Constants.SilverPen);
            }
        }
        public override ControlGrip[] GetControlGrips(LcElement element)
        {
            var lcAxisLine = element as LcAxisLine; //getHel
            var grips = new List<ControlGrip>();
            var gripStart = new ControlGrip
            {
                Element = lcAxisLine,
                Name = "Start",
                Position = lcAxisLine.AxisLine.Start
            };
            grips.Add(gripStart);
            var gripEnd = new ControlGrip
            {
                Element = lcAxisLine,
                Name = "End",
                Position = lcAxisLine.AxisLine.End
            };
            grips.Add(gripEnd);

            foreach (var lcAxisCircle in lcAxisLine.StartCircleHandle)
            {
                var gripCircle = new ControlGrip
                {
                    Element = lcAxisLine,
                    Name = "StartCircle",
                    Position = lcAxisCircle.LcCircle.Center
                };
                grips.Add(gripCircle);
            }
            foreach (var lcAxisCircle in lcAxisLine.EndCircleHandle)
            {
                var gripCircle = new ControlGrip
                {
                    Element = lcAxisLine,
                    Name = "EndCircle",
                    Position = lcAxisCircle.LcCircle.Center
                };
                grips.Add(gripCircle);
            }
            return grips.ToArray();
        }
        public override SnapPointResult SnapPoint(SnapRuntime snapRt, LcElement element, Vector2 point, bool forRef, Vector2 PrePoint = null)
        {

            var maxDistance = vportRt.GetSnapMaxDistance();
            var lcAxisLine = element as LcAxisLine;
            var sscur = SnapSettings.Current;
            var result = new SnapPointResult { Element = element };
            if (sscur.ObjectOn)
            {
                var line2d = lcAxisLine.AxisLine.Line;
                if (sscur.PointType.Has(SnapPointType.Endpoint))
                {
                    if ((point - line2d.Start).Length() <= maxDistance)
                    {
                        result.Point = line2d.Start;
                        result.Name = "Start";
                        result.Curves.Add(new SnapRefCurve(SnapPointType.Endpoint, line2d));
                    }
                    else if ((point - line2d.End).Length() <= maxDistance)
                    {
                        result.Point = line2d.End;
                        result.Name = "End";
                        result.Curves.Add(new SnapRefCurve(SnapPointType.Endpoint, line2d));
                    }
                }
            }
            if (sscur.PointType.Has(SnapPointType.Midpoint) && result.Point == null)
            {
                var line = lcAxisLine.AxisLine.Line;

                var cp = (line.Start + line.End) / 2;
                if ((point - cp).Length() <= maxDistance)
                {
                    result.Point = cp;
                    result.Name = "Mid";
                    result.Curves.Add(new SnapRefCurve(SnapPointType.Midpoint, line));
                }
            }
            //forRef时只捕捉端点，中点等，如果
            if (!forRef && result.Point == null)
            {
                var line = lcAxisLine.AxisLine.Line;

                var refPoints = snapRt.GetRefPoints(element);
                var lineLength = (line.End - line.Start).Length();
                var distance = GeoUtils.PointToLineDistance(line.Start, line.End, point, out Vector2 nearest, out double dirDistance);
                if (sscur.PointType.Has(SnapPointType.Nearest))
                {
                    //最近点必须在线段内进行测试
                    if (distance < maxDistance && dirDistance > 0 && dirDistance < lineLength)
                    {
                        result.Point = nearest;
                        result.Name = "Nearest";
                        result.Curves.Add(new SnapRefCurve(SnapPointType.Nearest, line));
                    }
                }
                //进行延长线上点捕捉，需要元素上有参考点
                if (sscur.PointType.Has(SnapPointType.ExtensionLine) && refPoints.Count > 0 && result.Point == null)
                {
                    if (distance < maxDistance)
                    {
                        result.Point = nearest;
                        result.Name = "Extension";
                        result.Curves.Add(new SnapRefCurve(SnapPointType.ExtensionLine, line));
                    }
                }
            }

            if (result.Point != null)
                return result;
            else
                return null;
        }

        public override SnapPointResult SnapLine(SnapRuntime snapRt, List<Vector2> vector2s, Vector2 point, bool forRef)
        {

            var maxDistance = vportRt.GetSnapMaxDistance();
            var sscur = SnapSettings.Current;
            var result = new SnapPointResult { };
            if (sscur.ObjectOn)
            {

                if (sscur.PointType.Has(SnapPointType.Intersection))
                {
                    foreach (Vector2 vector2 in vector2s)
                    {
                        if (point.DistanceTo(vector2) <= maxDistance)
                        {
                            result.Point = vector2;
                            result.Name = "Intersection";
                            result.Curves.Add(new SnapRefCurve(SnapPointType.Intersection, new Line2d(vector2, vector2)));
                        }
                    }
                }
            }
            if (result.Point != null)
                return result;
            else
                return null;
        }

        LcAxisLine _lcAxisLine;
        private string _gripName;
        Vector2 _position;
        public override void SetDragGrip(LcElement element, string gripName, Vector2 position, bool isEnd)
        {
            var lcAxisLine = element as LcAxisLine;
            _lcAxisLine = lcAxisLine;


            if (!isEnd)
            {
                _gripName = gripName;
                _position = position;
            }
            else
            {
                Vector2 dragpoint = position;

                if (this.vportRt.SnapRt?.Current != null)
                {
                    dragpoint = this.vportRt.SnapRt.Current.SnapPoint;
                }
                if (gripName == "Start")
                {
                    lcAxisLine.Set(start: dragpoint);
                }
                else if (gripName == "End")
                {
                    lcAxisLine.Set(end: dragpoint);
                }
            }

            //  DocumentManager.CurrentRecorder.EndAction();
        }

        public override void DrawDragGrip(SKCanvas canvas)
        {
            if (_lcAxisLine == null) return;

            var start = this.vportRt.ConvertWcsToScr(_lcAxisLine.AxisLine.Start);
            if (_gripName == "Start")
                start = this.vportRt.ConvertWcsToScr(_position);

            var end = this.vportRt.ConvertWcsToScr(_lcAxisLine.AxisLine.End);
            if (_gripName == "End")
                end = this.vportRt.ConvertWcsToScr(_position);

            canvas.DrawLine(start.ToSKPoint(), end.ToSKPoint(), Constants.draggingPen);
        }
    }
}
